/**
 * 数据备份控制器
 */

import type { Context } from 'elysia';
import { eq, desc, and } from 'drizzle-orm';
import { db } from '../db';
import { backups, users, products, cases, settings, uploads, systemLogs } from '../db/schema';
import { nanoid } from 'nanoid';
import { promises as fs } from 'fs';
import path from 'path';
import { successResponse, errorResponse, paginatedResponse, createPaginationMeta, ApiError, Logger, asyncHandler } from '../utils/response';
import { logUserOperation, logDatabaseOperation } from '../middleware/logger';
import type { AuthContext } from '../middleware/auth';

// 备份目录
const BACKUP_DIR = path.join(process.cwd(), 'backups');

/**
 * 确保备份目录存在
 */
async function ensureBackupDir(): Promise<void> {
  try {
    await fs.access(BACKUP_DIR);
  } catch {
    await fs.mkdir(BACKUP_DIR, { recursive: true });
  }
}

/**
 * 获取备份列表
 */
export const getBackups = asyncHandler(async ({ query, user }: AuthContext) => {
  const {
    page = '1',
    limit = '10',
    type,
    status
  } = query as any;

  const pageNum = parseInt(page);
  const limitNum = parseInt(limit);
  const offset = (pageNum - 1) * limitNum;

  // 构建查询条件
  const conditions = [];
  if (type) conditions.push(eq(backups.type, type));
  if (status) conditions.push(eq(backups.status, status));

  const whereClause = conditions.length > 0 ? and(...conditions) : undefined;

  // 查询数据
  const [backupList, totalResult] = await Promise.all([
    db.select()
      .from(backups)
      .where(whereClause)
      .orderBy(desc(backups.createdAt))
      .limit(limitNum)
      .offset(offset),
    db.select({ count: backups.id })
      .from(backups)
      .where(whereClause)
  ]);

  const total = totalResult.length;
  const pagination = createPaginationMeta(pageNum, limitNum, total);

  logDatabaseOperation('select', 'backups', backupList.length);
  logUserOperation(user?.id || 'anonymous', user?.username || 'anonymous', 'view', 'backups');

  Logger.info('Backups retrieved', { count: backupList.length, page: pageNum, limit: limitNum });
  return successResponse(
    paginatedResponse(backupList.map(backup => ({
      ...backup,
      tables: backup.tables ? JSON.parse(backup.tables) : []
    })), pagination).data,
    '获取备份列表成功'
  );
});

/**
 * 创建备份
 */
export const createBackup = asyncHandler(async ({ body, user }: AuthContext) => {
  const {
    name,
    description,
    tables: selectedTables = []
  } = body as any;

  if (!name) {
    throw ApiError.validation('备份名称不能为空');
  }

  // 确保备份目录存在
  await ensureBackupDir();

  const backupId = nanoid();
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
  const fileName = `backup_${timestamp}_${backupId}.sql`;
  const filePath = path.join(BACKUP_DIR, fileName);

  // 创建备份记录
  const backupData = {
    id: backupId,
    name,
    description: description || '',
    type: 'manual',
    status: 'processing',
    filePath,
    tables: JSON.stringify(selectedTables.length > 0 ? selectedTables : [
      'users', 'products', 'cases', 'settings', 'uploads', 'system_logs'
    ]),
    createdBy: user?.id
  };

  const [newBackup] = await db.insert(backups).values(backupData).returning();

  // 异步执行备份
  performBackup(backupId, filePath, selectedTables.length > 0 ? selectedTables : null)
    .catch(error => {
      Logger.error('Backup failed:', error);
      // 更新备份状态为失败
        db.update(backups)
          .set({ 
            status: 'failed', 
            error: (error as Error).message,
            completedAt: new Date().toISOString()
          })
          .where(eq(backups.id, backupId))
          .catch(err => Logger.error('Failed to update backup status:', err));
    });

  logUserOperation(user?.id || '', user?.username || '', 'create', 'backup', { backupId, name });

  Logger.info('Backup task created', { backupId, name, tables: selectedTables });
  return successResponse({
    ...newBackup,
    tables: JSON.parse(newBackup.tables || '[]')
  }, '备份任务已创建，正在后台处理');
});

/**
 * 执行备份操作
 */
async function performBackup(backupId: string, filePath: string, selectedTables?: string[]): Promise<void> {
  const startTime = Date.now();
  
  try {
    // 获取所有表的数据
    const tableData: Record<string, any[]> = {};
    
    if (!selectedTables || selectedTables.includes('users')) {
      tableData.users = await db.select().from(users);
    }
    if (!selectedTables || selectedTables.includes('products')) {
      tableData.products = await db.select().from(products);
    }
    if (!selectedTables || selectedTables.includes('cases')) {
      tableData.cases = await db.select().from(cases);
    }
    if (!selectedTables || selectedTables.includes('settings')) {
      tableData.settings = await db.select().from(settings);
    }
    if (!selectedTables || selectedTables.includes('uploads')) {
      tableData.uploads = await db.select().from(uploads);
    }
    if (!selectedTables || selectedTables.includes('system_logs')) {
      tableData.system_logs = await db.select().from(systemLogs);
    }

    // 生成SQL备份文件
    let sqlContent = `-- 数据库备份文件\n-- 创建时间: ${new Date().toISOString()}\n-- 备份ID: ${backupId}\n\n`;

    for (const [tableName, rows] of Object.entries(tableData)) {
      if (rows.length === 0) continue;
      
      sqlContent += `-- 表: ${tableName}\n`;
      sqlContent += `DELETE FROM ${tableName};\n`;
      
      for (const row of rows) {
        const columns = Object.keys(row);
        const values = Object.values(row).map(val => 
          val === null ? 'NULL' : `'${String(val).replace(/'/g, "''")}'`
        );
        
        sqlContent += `INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${values.join(', ')});\n`;
      }
      
      sqlContent += '\n';
    }

    // 写入文件
    await fs.writeFile(filePath, sqlContent, 'utf8');
    
    // 获取文件大小
    const stats = await fs.stat(filePath);
    const fileSize = stats.size;
    
    const duration = Date.now() - startTime;

    // 更新备份状态
    await db.update(backups)
      .set({ 
        status: 'completed',
        fileSize,
        completedAt: new Date().toISOString()
      })
      .where(eq(backups.id, backupId));

    Logger.info(`Backup completed: ${backupId}`, { duration, fileSize });
  } catch (error) {
    const duration = Date.now() - startTime;
    Logger.error(`Backup failed: ${backupId}`, { error: (error as Error).message, duration });
    throw error;
  }
}

/**
 * 下载备份文件
 */
export const downloadBackup = async ({ params, user, set }: AuthContext) => {
  try {
    const { id } = params as { id: string };
    
    const backup = await db.select()
      .from(backups)
      .where(eq(backups.id, id))
      .limit(1);
    
    if (backup.length === 0) {
      set.status = 404;
      return errorResponse('备份不存在');
    }
    
    const backupRecord = backup[0]!;
    
    if (backupRecord.status !== 'completed') {
      set.status = 400;
      return errorResponse('备份尚未完成或已失败');
    }
    
    if (!backupRecord.filePath) {
      set.status = 400;
      return errorResponse('备份文件路径不存在');
    }
    
    try {
      await fs.access(backupRecord.filePath);
    } catch {
      set.status = 404;
      return errorResponse('备份文件不存在');
    }
    
    logUserOperation(user?.id || '', user?.username || '', 'download', 'backup', { backupId: id });
    
    // 返回文件内容
    const fileContent = await fs.readFile(backupRecord.filePath, 'utf8');
    
    set.headers = {
      'Content-Type': 'application/sql',
      'Content-Disposition': `attachment; filename="${backupRecord.name}.sql"`
    };
    
    return fileContent;
  } catch (error) {
    Logger.error('Download backup error:', error);
    set.status = 500;
    return errorResponse('下载备份文件失败');
  }
};

/**
 * 删除备份
 */
export const deleteBackup = async ({ params, user, set }: AuthContext) => {
  try {
    const { id } = params as { id: string };
    
    const backup = await db.select()
      .from(backups)
      .where(eq(backups.id, id))
      .limit(1);
    
    if (backup.length === 0) {
      set.status = 404;
      return errorResponse('备份不存在');
    }
    
    const backupRecord = backup[0]!;
    
    // 删除文件
    if (backupRecord.filePath) {
      try {
        await fs.unlink(backupRecord.filePath);
      } catch (error) {
        Logger.warn('Failed to delete backup file:', error);
      }
    }
    
    // 删除数据库记录
    await db.delete(backups).where(eq(backups.id, id));
    
    logUserOperation(user?.id || '', user?.username || '', 'delete', 'backup', { backupId: id });
    
    return successResponse(null, '备份删除成功');
  } catch (error) {
    Logger.error('Delete backup error:', error);
    set.status = 500;
    return errorResponse('删除备份失败');
  }
};

/**
 * 恢复备份
 */
export const restoreBackup = async ({ params, user, set }: AuthContext) => {
  try {
    const { id } = params as { id: string };
    
    const backup = await db.select()
      .from(backups)
      .where(eq(backups.id, id))
      .limit(1);
    
    if (backup.length === 0) {
      set.status = 404;
      return errorResponse('备份不存在');
    }
    
    const backupRecord = backup[0]!;
    
    if (backupRecord.status !== 'completed') {
      set.status = 400;
      return errorResponse('备份尚未完成或已失败');
    }
    
    if (!backupRecord.filePath) {
      set.status = 400;
      return errorResponse('备份文件路径不存在');
    }
    
    try {
      await fs.access(backupRecord.filePath);
    } catch {
      set.status = 404;
      return errorResponse('备份文件不存在');
    }
    
    // 读取并执行SQL文件
    const sqlContent = await fs.readFile(backupRecord.filePath, 'utf8');
    const statements = sqlContent.split(';').filter(stmt => stmt.trim() && !stmt.trim().startsWith('--'));
    
    const startTime = Date.now();
    
    // 执行SQL语句
    for (const statement of statements) {
      if (statement.trim()) {
        await db.run(statement.trim());
      }
    }
    
    const duration = Date.now() - startTime;
    
    logUserOperation(user?.id || '', user?.username || '', 'restore', 'backup', { 
      backupId: id, 
      duration,
      statements: statements.length 
    });
    
    return successResponse(null, '数据恢复成功');
  } catch (error) {
    Logger.error('Restore backup error:', error);
    set.status = 500;
    return errorResponse('数据恢复失败');
  }
};